#ifndef _Timer_H__
#define _Timer_H__

#include "stdafx.h"
#include "Logger.h"
#include "Singleton.h"
#include <winbase.h>

#define _MICRO_CHAR char(230)

namespace GeorgeLib
{
	///	@brief
	///	Retrieves the system's time, provides a counter and a time delay check.

	///	@details
	///	Provides functions to get the time, count the time, and check if an amount of time has been passed.
	///	Every function has two types, one that is precise

	/**
		\n\n
		How to use :
		@code
		Timer *timer = Timer::getInstance();

		cout << timer->GetTime() << endl;					// get system time

		int iCounter, iTimer;								// variables for counter and delay
		timer->StartCounter(iCounter);						// start counter

		// activity to be timed...

		cout << timer->GetCounter(iCounter) << endl;		// end counter

		cout << "Waiting 2 seconds...\t";
		while(1)											// loop to get a delay
		{
		if( timer->getDelay(2000, iTimer) )				// check for delay
		{
		cout << "Done!" << endl;
		break;
		}
		}

		cout << timer->GetTimePrecise() << endl;			// get system time

		double dCounter, dTimer;							// variables for precise counter and delay
		timer->StartCounterPrecise(dCountertime);

		// activity to be timed...

		cout << timer->GetCounterPrecise(dCounter) << endl;	// end counter

		cout << "Waiting 2 seconds...\t";
		while(1)											// loop to get a delay
		{
		if( timer->getDelayPrecise(2000000, dTimer) )	// check for delay
		{
		cout << "Done!" << endl;
		break;
		}
		}

		@endcode
		**/

	class DLLEXPORT Timer : public Singleton <Timer>
	{
	private:

		///	Frequency of the high-resolution performance counter in counts/microsecond
		static	double	PerformanceCounterFreq;

	public:

		///	Constructor
		Timer(void);

		///	Destructor
		~Timer(void);

		///	Retrieve the system time
		/**	@note This function has precision of at least 5 milliseconds
			@return the system time <b>in milliseconds</b>	**/
		int		GetTime(void);

		///	Starts a counter
		/**	@note Call Timer::GetCounter() to stop the counter
			@param prevTime the external variable to keep check of the time passed	**/
		void	StartCounter(int & prevTime);

		///	Stops a counter
		/**	@warning Call Timer::StartCounter() first!
			@param prevTime the external variable that is passed in
			from the last call to Timer::StartCounter()
			@return the amount of time <b>in milliseconds</b> that has passed since
			the last call to Timer::StartCounter()	**/
		int		GetCounter(int prevTime);

		///	Checks if a specified time has passed
		/**	@warning This function only works in a loop!
			@warning \c prevTime must be zero before calling this function
			@param delay the specified amount of time to check for, <b>in milliseconds</b>
			@param prevTime an external variable to keep track of the time passed.
			must be zero before the first call to this function
			@return true if the specified time has elapsed, else false	**/
		bool	GetDelay(const int delay, int & prevTime);

		///	Retreive the high precision system time
		/**	@note This function has a precision of at least 1 microseconds
			@return the system time <b>in microseconds</b>	**/
		double	GetTimePrecise(void);

		///	Start a high precision counter
		/**	@note Call Timer::GetCounterPrecise() to stop the counter
			@param prevTime the external variable to keep check of the time passed	**/
		void	StartCounterPrecise(double & prevTime);

		///	Stops a high precision counter
		/**	@warning Call Timer::StartCounterPrecise() first!
			@param prevTime the external variable that is passed in
			from the last call to Timer::StartCounterPrecise()
			@return the amount of time <b>in microseconds</b> that has passed since
			the last call to Timer::StartCounterPrecise()	**/
		double	GetCounterPrecise(double prevTime);

		///	Checks with high precision if a specified time has passed
		/**	@warning This function only works in a loop!
			@warning \c prevTime must be zero before calling this function
			@param delay the specified amount of time to check for <b>in microseconds</b>
			@param prevTime an external variable to keep track of the time passed
			@return true if the specified time has elapsed, else false	**/
		bool	GetDelayPrecise(const double delay, double & prevTime);
	};
} /// namespace GeorgeLib

#endif // _Timer_H__ //